package com.org.platform.utils;

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class LocalDateUtil {

  public final static String FORMAT_PATTERN1 = "yyyy-MM-dd HH:mm:ss";
  public final static String FORMAT_PATTERN2 = "yyyyMMddHHmmss";
  public final static String FORMAT_PATTERN3 = "yyyy-MM-dd";
  public final static String FORMAT_PATTERN4 = "yyyyMMdd";
  public final static String FORMAT_PATTERN5 = "MMdd";
  public static final String EARLY_TIME = "00:00:00";
  public static final String LATE_TIME = "23:59:59";

  /**
   * 将localDate 按照一定的格式转换成String
   *
   * @param localDate
   * @param pattern
   * @return
   */
  public static String localDateFormat(LocalDate localDate, String pattern) {
    return localDate.format(DateTimeFormatter.ofPattern(pattern));
  }

  /**
   * 将localDateTime 按照一定的格式转换成String
   *
   * @param localDateTime
   * @param pattern
   * @return
   */
  public static String localDateTimeFormat(LocalDateTime localDateTime, String pattern) {
    return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
  }

  /**
   * 得到某个日期在这一天中时间最早的日期对象
   */
  public static String getEarlyInTheDay(LocalDate localDate) {
    return localDateFormat(localDate, FORMAT_PATTERN3) + " " + EARLY_TIME;
  }

  /**
   * 得到某个日期在这一天中时间最晚的日期对象
   */
  public static String getLastInTheDay(LocalDate localDate) {
    return localDateFormat(localDate, FORMAT_PATTERN3) + " " + LATE_TIME;
  }

  /**
   * 将String 按照pattern 转换成LocalDate
   *
   * @param time
   * @param pattern
   * @return
   */
  public static LocalDate localDateParse(String time, String pattern) {
    return LocalDate.parse(time, DateTimeFormatter.ofPattern(pattern));
  }

  /**
   * 将String 按照pattern 转换成LocalDateTime
   *
   * @param time
   * @param pattern
   * @return
   */
  public static LocalDateTime localDateTimeParse(String time, String pattern) {
    return LocalDateTime.parse(time, DateTimeFormatter.ofPattern(pattern));
  }

  /**
   * 将date转换成String
   *
   * @param date
   * @param pattern
   * @return
   */
  public static String dateFormat(Date date, String pattern) {
    return localDateTimeFormat(dateToLocalDateTime(date), pattern);
  }

  /**
   * 将LocalDate 转换成 Date
   *
   * @param localDate
   * @return
   */
  public static Date localDateToDate(LocalDate localDate) {
    ZoneId zoneId = ZoneId.systemDefault();
    ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
    return Date.from(zdt.toInstant());
  }

  /**
   * 将LocalDateTime 转换成 Date
   *
   * @param localDateTime
   * @return
   */
  public static Date localDateTimeToDate(LocalDateTime localDateTime) {
    ZoneId zoneId = ZoneId.systemDefault();
    ZonedDateTime zdt = localDateTime.atZone(zoneId);
    return Date.from(zdt.toInstant());
  }

  /**
   * 将 Date 转换成LocalDate atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
   *
   * @param date
   * @return
   */
  public static LocalDate dateToLocalDate(Date date) {
    Instant instant = date.toInstant();
    ZoneId zoneId = ZoneId.systemDefault();
    return instant.atZone(zoneId).toLocalDate();
  }

  /**
   * 将 Date 转换成LocalDateTime atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
   *
   * @param date
   * @return
   */
  public static LocalDateTime dateToLocalDateTime(Date date) {
    Instant instant = date.toInstant();
    ZoneId zoneId = ZoneId.systemDefault();
    return instant.atZone(zoneId).toLocalDateTime();
  }

  /**
   * 计算两个LocalDateTime 之间的毫秒数
   *
   * @param time1
   * @param time2
   * @return
   */
  public static Long minusToMillsLocalDateTime(LocalDateTime time1, LocalDateTime time2) {
    return Duration.between(time1, time2).toMillis();
  }

  /**
   * 计算两个LocalTime 之间的毫秒数
   *
   * @param time1
   * @param time2
   * @return
   */
  public static Long minusToMillsLocalTime(LocalTime time1, LocalTime time2) {
    return Duration.between(time1, time2).toMillis();
  }

  /**
   * 计算两个LocalDate 之间的毫秒数
   *
   * @param time1
   * @param time2
   * @return
   */
  public static Long minusToMillsLocalDate(LocalDate time1, LocalDate time2) {
    return Duration.between(time1, time2).toMillis();
  }

  /**
   * 计算两个LocalDate 之间的Period
   *
   * @param time1
   * @param time2
   * @return
   */
  public static Period periodLocalDate(LocalDate time1, LocalDate time2) {
    return Period.between(time1, time2);
  }

  /**
   * 计算两个Date 之间的Period
   *
   * @param date1
   * @param date2
   * @return
   */
  public static Period periodDate(Date date1, Date date2) {
    return periodLocalDate(dateToLocalDate(date1), dateToLocalDate(date2));
  }

  /**
   * 计算两个time 之间的差值
   *
   * @param startTime
   * @param endTime
   * @return
   */
  public static long unitDate(LocalDate startTime, LocalDate endTime, ChronoUnit chronoUnit) {
    return startTime.until(endTime, chronoUnit);
  }

  /**
   * 计算两个time 之间的差值
   *
   * @param startTime
   * @param endTime
   * @return
   */
  public static long unitDate(LocalDate startTime, LocalDate endTime) {
    return unitDate(startTime, endTime, ChronoUnit.DAYS);
  }

  /**
   * 计算两个Date 之间的差值
   *
   * @param startTime
   * @param endTime
   * @return
   */
  public static long unitDate(Date startTime, Date endTime, ChronoUnit chronoUnit) {
    return unitDate(dateToLocalDate(startTime), dateToLocalDate(endTime), chronoUnit);
  }

  /**
   * 计算两个Date 之间的差值
   *
   * @param startTime
   * @param endTime
   * @return
   */
  public static long unitDate(Date startTime, Date endTime) {
    return unitDate(startTime, endTime, ChronoUnit.DAYS);
  }

  /**
   * 计算两个Date之间的 Period
   *
   * @param time1
   * @param time2
   * @return
   */
  public static Long minusToMillsDate(Date time1, Date time2) {
    return minusToMillsLocalDateTime(dateToLocalDateTime(time1), dateToLocalDateTime(time2));
  }

  public static void main(String args[]) {
    Date date1 = new Date();
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println(localDateFormat(LocalDate.now(), FORMAT_PATTERN3));
    System.out.println(localDateTimeFormat(LocalDateTime.now(), FORMAT_PATTERN1));
    System.out.println(localDateTimeFormat(LocalDateTime.now(), FORMAT_PATTERN2));
    System.out.println(localDateTimeToDate(LocalDateTime.now()));
    System.out.println(dateFormat(new Date(), FORMAT_PATTERN4));
    System.out.println("minusToMillsLocalDateTime:"+minusToMillsLocalDateTime(LocalDateTime.now(), LocalDateTime.now().minusSeconds(1)));
    System.out.println(minusToMillsDate(date1, new Date()));
    System.out.println(localDateParse("2018-06-12", FORMAT_PATTERN3));
    System.out.println(localDateTimeParse("2018-06-12 16:04:43", FORMAT_PATTERN1));
    Period p = periodDate(date1, new Date());
    System.out.println("year:" + p.getYears() + "month:" + p.getMonths() + "day:" + p.getDays());
    System.out.println("----------------------------------------------------------------");
    Date date2 = localDateToDate(LocalDate.now().minusMonths(1).minusDays(2));
    Date date3 = localDateToDate(LocalDate.now());
    Period p2 = periodDate(date2, date3);
    System.out.println("year:" + p2.getYears() + "month:" + p2.getMonths() + "day:" + p2.getDays());
    System.out.println("----------------------------------------------------------------");
    Period p1 = periodLocalDate(LocalDate.now().minusDays(2), LocalDate.now());
    System.out.println("year:" + p1.getYears() + "month:" + p1.getMonths() + "day:" + p1.getDays());

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    LocalDateTime localDateTime = LocalDateTime.now();
    String now = localDateTime.format(dtf);
    System.out.println(now);
    LocalDateTime weekTime = localDateTime.minusWeeks(7);
    now = weekTime.format(dtf);
    System.out.println(now);

    int year = localDateTime.getYear();
    int month = localDateTime.getMonthValue();
    int day = localDateTime.getDayOfMonth();
    System.out.println("time-year:" + year + "month:" + month + "day:" + day);

    // 取本月第1天：
    LocalDateTime firstDayOfThisMonth = localDateTime.with(TemporalAdjusters.firstDayOfMonth()); // 2014-12-01
    // 取本月第2天：
    LocalDateTime secondDayOfThisMonth = localDateTime.withDayOfMonth(2); // 2014-12-02
    // 取本月最后一天，再也不用计算是28，29，30还是31：
    LocalDateTime lastDayOfThisMonth = localDateTime.with(TemporalAdjusters.lastDayOfMonth()); // 2014-12-31
    // 取下一天：
    LocalDateTime firstDayOf2015 = lastDayOfThisMonth.plusDays(1); // 变成了2015-01-01
    // 取2015年1月第一个周一，这个计算用Calendar要死掉很多脑细胞：
    LocalDate firstMondayOf2015 = LocalDate.parse("2019-06-11").with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); // 2015-01-05
    System.out.println(firstDayOfThisMonth);
    System.out.println(secondDayOfThisMonth);
    System.out.println(lastDayOfThisMonth);
    System.out.println(firstDayOf2015);
    System.out.println(firstMondayOf2015);
    furture();
  }

  public static void furture() {

    long startTime = System.currentTimeMillis();
    Callable<Integer> calculateCallable = new Callable<Integer>() {
      @Override
      public Integer call() throws Exception {
        // TODO Auto-generated method stub
        Thread.sleep(2000);//模拟耗时时间
        int result = 1 + 2;
        return result;
      }
    };
    FutureTask<Integer> calculateFutureTask = new FutureTask<>(calculateCallable);
    Thread t1 = new Thread(calculateFutureTask);
    t1.start();
    //现在加入Thread运行的是一个模拟远程调用耗时的服务，并且依赖他的计算结果（比如网络计算器）
    try {
      //模拟耗时任务，主线程做自己的事情，体现多线程的优势
      Thread.sleep(3000);
      int a = 3 + 5;
      Integer result = calculateFutureTask.get();
      System.out.println("result = " + (a + result));//模拟主线程依赖子线程的运行结果
      long endTime = System.currentTimeMillis();
      System.out.println("time = " + (endTime - startTime) + "ms");
    } catch (InterruptedException | ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

}
